import _ from 'lodash'
export function getCookie(key: string) {
  if (document.cookie) {
    //判断是否有cookie
    const arr = document.cookie.split('; ') //拆分所有cookie
    // 通过key 查找value
    for (let i = 0; i < arr.length; i++) {
      const item = arr[i].split('=') //将cookie数据拆分成key value
      if (item[0] === key) {
        return item[1]
      } //找到key 返回value
    }
    return '' //如果循环结束 都没有 则返回空字符串
  }
}

export function setCookie(key: string, value: string, day: number) {
  if (typeof day === 'number') {
    const d = new Date()
    d.setDate(d.getDate() + day)
    document.cookie = `${key}=${value};expires=${d};path=/`
  } else {
    document.cookie = `${key}=${value};path=/`
  }
}

//传入一个数组  根据关联属性  进行拆分  做一个元素回调
export function relevancyAttSplit(
  arr: any[],
  sym: any,
  pSym: any,
  callback?: () => unknown,
) {
  const result: any[] = []
  arr.forEach((i: any) => {
    if (!i[pSym]) result.push(i) //先添加初始值 没有pSym
  })

  const parentIdArr = [...new Set(arr.map(i => i[pSym]))].filter(i => i) //提取pSym,去重 过滤

  function inside(filterArr: any[], pid: any) {
    const _result: any[] = filterArr.filter((item: any) => item[pSym] === pid) //过滤出来一个数组,这就是需要的数据,但是还需要挂载子数组

    const newArr: any[] = filterArr.filter(function (item) {
      //过滤掉已经使用的数组,剩下还没有分配的数组
      return !_result.find(function (ii) {
        return item[sym] === ii[sym]
      })
    })
    const _parentIdArr = [...new Set(newArr.map(i => i[pSym]))]

    _parentIdArr.length &&
      _result.forEach(item => {
        //剩下的数组还有内容就继续执行
        if (_parentIdArr.some(i => i === item[sym])) {
          //如果有检测到父id就执行一次回调函数
          item.children = inside(newArr, item[sym])
        }
      })
    callback &&
      _result.forEach(item => {
        callback(item)
      })
    return _result
  }

  result.forEach(item => {
    if (parentIdArr.some(i => i === item[sym])) {
      //如果有,就调用这个方法
      item.children = inside(
        arr.filter(i => i[pSym]),
        item[sym],
      )
    }
    callback && callback(item)
  })

  console.log(result.length === 1 ? result[0] : result)
  return result.length === 1 ? result[0] : result
}

//传入一个数组tree  以及子集children  目标属性id  目标属性值idValue  进行查找做 回调操作 callback
export function findItemOperation(
  tree: any[],
  children: string,
  id: string,
  idValue: any,
  callback?: () => void,
  callPut?: () => void,
) {
  let result: any[] = _.cloneDeep(tree)

  Array.isArray(result) &&
    result.length &&
    result.forEach(item => {
      item.showIcon = false
      //没有中断操作会导致性能浪费 后续扩充
      callback && item[id] === idValue && (item = callback(item, idValue))

      if (item && item[children] && item[children].length) {
        try {
          item[children] = findItemOperation(
            item[children],
            children,
            id,
            idValue,
            callback,
          )
        } catch (error) {
          console.log(error)
        }
      }
    })

  return result
}

export function handleMoney(value: number | string, num: number | string = 2) {
  num = num > 0 && num <= 20 ? num : 2
  value = parseFloat((value + '').replace(/[^\d\.-]/g, '')).toFixed(num) + '' //将金额转成比如 123.45的字符串
  const valueArr = value.split('.')[0].split('').reverse() //将字符串的数变成数组
  const valueFloat = value.split('.')[1] // 取到 小数点后的值
  let valueString = ''
  for (let i = 0; i < valueArr.length; i++) {
    valueString +=
      valueArr[i] + ((i + 1) % 3 == 0 && i + 1 != valueArr.length ? ',' : '') //循环 取数值并在每三位加个','
  }
  const money = valueString.split('').reverse().join('') + '.' + valueFloat //拼接上小数位
  return money
}

// 深拷贝的基本实现
// 优化1：数组or对象
// 优化2：函数，函数进行复用，函数进行赋值而不是额外拷贝一个新的函数，如果是函数则直接返回
// 优化3：symbol类型
// set和map只是做了浅层拷贝
// 优化4：set处理
// 优化5：map处理
function isObject(value: any) {
  const valueType = typeof value
  return value !== null && (valueType === 'object' || valueType === 'function')
}

function deepClone(originValue: any) {
  // instanceof判断某个对象是否为真实的构造函数类型
  // 优化4，判断是否是一个Set类型
  if (originValue instanceof Set) {
    return new Set([...originValue])
  }

  // 优化5，判断是否是一个Map类型
  if (originValue instanceof Map) {
    return new Map([...originValue])
  }

  // 优化3，判断如果是Symbol的value, 那么创建一个新的Symbol
  if (typeof originValue === 'symbol') {
    return Symbol(originValue.description)
  }

  // 优化2，判断如果是函数类型, 那么直接使用同一个函数
  if (typeof originValue === 'function') {
    return originValue
  }

  // 判断传入的originValue是否是一个对象类型
  // 如果不是对象类型，则直接返回，做一个赋值操作，将旧的值赋值给新的对象
  if (!isObject(originValue)) {
    return originValue
  }

  // 优化1，判断传入的对象是数组, 还是对象
  const newObject = Array.isArray(originValue) ? [] : {}
  for (const key in originValue) {
    newObject[key] = deepClone(originValue[key])
  }
  // symbol无法当作key被遍历，所以需要另外处理
  // 对Symbol的key进行特殊的处理
  const symbolKeys = Object.getOwnPropertySymbols(originValue)
  for (const sKey of symbolKeys) {
    newObject[sKey] = deepClone(originValue[sKey])
  }
  return newObject
}
interface DogInterface {
  run(): void
}
interface CatInterface {
  jump(): void
}

const pet: DogInterface & CatInterface = { run() {}, jump() {} }

interface Square {
  kind: 'square'
  size: number
}
interface Rectangle {
  kind: 'rectangle'
  width: number
  height: number
}

console.log(area({ kind: 'square', size: 10 })) // 100 // 现在要添加一个形状：圆形。需要定义接口Circle、为Shape添加联合类型Circle，然后为area函数内增加一个case。但是，如果我们忘了修改area函数，会发生什么？
interface Circle {
  kind: 'circle'
  r: number
}
type Shape = Square | Rectangle | Circle
console.log(area({ kind: 'circle', r: 10 })) // undefined，这里并不报错，并不符合我们的预期。我们希望bug能够及时暴露出来，增加程序的稳定性。 做如下改动：
function area(s: Shape) {
  switch (s.kind) {
    case 'square':
      return s.size * s.size
    case 'rectangle':
      return s.height * s.width
    case 'circle':
      return Math.PI * s.r
    default:
      return ((e: any) => {
        throw new Error(`没有定义 ${s} 的面积计算方式`)
      })(s) // 这一步很重要，一定要在这里抛出异常
  }
}
